<?php

namespace app\api\service\weixinApp;

use app\common\BaseHelper;
use app\lib\exception\PayException;
use app\api\controller\Base;

use think\Exception;
use think\Loader;
use think\Log;

Loader::import('WxPay.WxPay',EXTEND_PATH,'.AppApi.php');

/**
 * 微信支付类，要实现支付需要继承此类
 * 生成微信预订单、统一下单、签名算法、返回小程序需要的支付参数
 * Class BasePay
 * @package app\api\service\weixin
 */
class BasePay extends Base
{

    /**
     * 支付入口方法
     * @param $totalPrice 订单金额
     * @param $productName 商品名称
     * @param $openid 小程序用户openid
     * @param $orderNO 订单号
     * @param $pay_back_url 支付回调地址
     * @return array
     */
    public function run($totalPrice,$productName,$openid,$orderNO,$pay_back_url){
        return $this->makeWxPreOrder($totalPrice,$productName,$openid,$orderNO,$pay_back_url);
    }

    /**
     * 生成微信预订单
     * @param $totalPrice
     * @return array
     */
    private function makeWxPreOrder($totalPrice,$productName,$openid,$orderNO,$pay_back_url){
        $wxOrderData = new \WxPayUnifiedOrder();
        $wxOrderData->SetOut_trade_no($orderNO);
        $wxOrderData->SetTrade_type('APP');
        $wxOrderData->SetTotal_fee($totalPrice);
        $wxOrderData->SetBody($productName);
        $wxOrderData->SetNotify_url($pay_back_url);

        return $this->getPaySignature($wxOrderData);
    }

    /**
     * 请求微信统一下单接口返回给客户端一组支付参数
     */
    private function getPaySignature($wxOrderData){
        $wxOrder = \WxPayAPPApi::unifiedOrder($wxOrderData);
        if($wxOrder['return_code'] != 'SUCCESS' || $wxOrder['result_code'] != 'SUCCESS'){
            Log::record($wxOrder,'error');
            Log::record('获取预支付订单失败','error');
        }
        if($wxOrder['return_code'] == 'FAIL'){
            throw new PayException([
                'msg' => $wxOrder['return_msg']
            ]);
        }
        $this->recordPreOrder($wxOrder);

        // 执行第二次签名，才能返回给客户端使用
        return $this->sign($wxOrder);
    }

    protected function recordPreOrder($wxOrder){
        //存储预支付交易会话标识 子类需要覆盖
    }

    /**
     * 生成签名
     */
    private function sign($wxOrder){
//        $jsApiPayData = new \WxPayJsApiPay();
//        $jsApiPayData->SetAppid(config('wx.app.app_id'));
//        $jsApiPayData->SetTimeStamp((string)time());
//        $jsApiPayData->SetNonceStr(BaseHelper::getUUID());
//        $jsApiPayData->SetPackage('prepay_id='.$wxOrder['prepay_id']);
//        $jsApiPayData->SetSignType('md5');
//        $sign = $jsApiPayData->MakeSign();

        $data['appid'] = config('wx.app.app_id');
        //$data['noncestr'] = BaseHelper::getUUID();
        $data['noncestr'] = strtoupper(BaseHelper::getUUID());
        $data['package'] = 'Sign=WXPay';
        $data['partnerid'] = config('wx.mchid');
        $data['prepayid'] = $wxOrder['prepay_id'];
        $data['timestamp'] = time();

        $sign = $this->getSign($data);
        $data['sign'] = $sign;

        return $data;
        //return $this->arrToString($data); // 和支付宝一致，转为字符串
    }

    /**
     * 生成签名
     */
    private function getSign($params)
    {
        //签名步骤一：按字典序排序参数
        ksort($params);
        $string = $this->ToUrlParams($params);
        //签名步骤二：在string后加入KEY
        $string = $string . "&key=" . config('wx.key');
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    public function ToUrlParams($params)
    {
        $buff = "";
        foreach ($params as $k => $v)
        {
            if($k != "sign" && $v != "" && !is_array($v)){
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }

    //为微信官方返回的数据类型做准备
    public function arrToString($params)
    {
        ksort($params); // 将参数数组按照参数名ASCII码从小到大排序

        foreach ($params as $key => $item) {
            if (!empty($item)) { // 剔除参数值为空的参数
                if ($v = 'Sign=WXPay') {
                    $newArr[] = $key.'='.urlencode($item);
                } else {
                    $newArr[] = $key.'='.$item;
                }
                //$newArr[] = $key.'='.$item; // 整合新的参数数组
            }
        }
        $stringA = implode("&", $newArr);

        return $stringA;
    }
}